package com.hc.javassist;

import com.android.build.api.transform.DirectoryInput;
import com.android.build.api.transform.Format;
import com.android.build.api.transform.JarInput;
import com.android.build.api.transform.QualifiedContent;
import com.android.build.api.transform.Status;
import com.android.build.api.transform.Transform;
import com.android.build.api.transform.TransformException;
import com.android.build.api.transform.TransformInput;
import com.android.build.api.transform.TransformInvocation;
import com.android.build.gradle.BaseExtension;
import com.android.build.gradle.internal.pipeline.TransformManager;

import org.gradle.api.Project;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

public class ClassTransform extends Transform {
    BaseExtension extension;
    ClassPool classPool = ClassPool.getDefault();
    @Override
    public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        super.transform(transformInvocation);
        System.out.println("-----transform()-----");
        List<File> fileList = extension.getBootClasspath();
        try {
            for (File file:fileList){
                    classPool.appendClassPath(file.getAbsolutePath());
            }
        } catch (NotFoundException e) {
            throw new RuntimeException(e);
        }
        Collection<TransformInput> collectionTransformInput = transformInvocation.getInputs();
        for (TransformInput transformInput:collectionTransformInput){
            Collection<DirectoryInput> directoryCollection = transformInput.getDirectoryInputs();
            for(DirectoryInput directoryInput:directoryCollection){
                File file = directoryInput.getFile();
                try {
                    classPool.insertClassPath(file.getAbsolutePath());
                } catch (NotFoundException e) {
                    throw new RuntimeException(e);
                }
                findTarget(file,file.getAbsolutePath());
                File dirPath = transformInvocation.getOutputProvider().getContentLocation(directoryInput.getName()
                        , directoryInput.getContentTypes(), directoryInput.getScopes(), Format.DIRECTORY);
                System.out.printf("DirPath"+dirPath.getAbsolutePath());
            }
            Collection<JarInput> jarInputCollection = transformInput.getJarInputs();
            for (JarInput jarInput:jarInputCollection){
                File jarPath = transformInvocation.getOutputProvider().getContentLocation(jarInput.getName()
                        , jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR);
                System.out.printf("JarPath"+jarPath.getAbsolutePath());
            }
        }
    }

    private void findTarget(File file, String name) {
        if(file.isDirectory()){
            File[] files = file.listFiles();
            for (File f:files){
                findTarget(f,name);
            }
        }else {
            if(file.getAbsolutePath().endsWith(".class")){
                editTarget(file.getAbsolutePath(),name);
            }
        }
    }

    private void editTarget(String s1, String s2) {
        if(!s1.contains("R$") && !s1.contains("R.class") && !s1.contains("BuildConfig.class")){
            String className = s1.replace(s2, "").replace("\\", ".").replace(".class", "").substring(1);
            try {
                CtClass ctClass = classPool.get(className);
                addCode(ctClass,s2);
            } catch (NotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void addCode(CtClass ctClass, String name) {
        ctClass.defrost();
        CtMethod[] methods = ctClass.getDeclaredMethods();
        for (CtMethod method:methods){
            try {
                method.insertBefore("if(true){}");
            } catch (CannotCompileException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            ctClass.writeFile(name);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        ctClass.detach();
    }

    public ClassTransform(BaseExtension baseExtension){
        System.out.println("-----ClassTransform()-----");
        this.extension = baseExtension;
    }
    @Override
    public String getName() {
        System.out.println("-----getName()-----");
        return "ClassTransform";
    }

    @Override
    public Set<QualifiedContent.ContentType> getInputTypes() {
        System.out.println("-----getInputTypes()-----");
        return TransformManager.CONTENT_CLASS;
    }

    @Override
    public Set<? super QualifiedContent.Scope> getScopes() {
        System.out.println("-----getScopes()-----");
        return TransformManager.SCOPE_FULL_PROJECT;
    }

    @Override
    public boolean isIncremental() {
        return false;
    }
}
